/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bef.core.action.modify;

import com.inspur.edp.bef.api.action.VoidActionResult;
import com.inspur.edp.bef.api.action.assembler.IBEActionAssembler;
import com.inspur.edp.bef.api.be.IBEContext;
import com.inspur.edp.bef.api.be.IBENodeEntity;
import com.inspur.edp.bef.api.be.IBENodeEntityContext;
import com.inspur.edp.bef.api.exceptions.BefEngineException;
import com.inspur.edp.bef.api.exceptions.ErrorCodes;
import com.inspur.edp.bef.core.action.AuthorityUtil;
import com.inspur.edp.bef.core.action.base.ActionUtil;
import com.inspur.edp.bef.core.lock.LockUtils;
import com.inspur.edp.bef.core.session.FuncSessionManager;
import com.inspur.edp.bef.entity.exception.BefExceptionBase;
import com.inspur.edp.bef.entity.exception.ExceptionLevel;
import com.inspur.edp.bef.spi.action.AbstractAction;
import com.inspur.edp.cef.entity.changeset.IChangeDetail;
import com.inspur.edp.cef.entity.changeset.ModifyChangeDetail;
import com.inspur.edp.cef.entity.changeset.ValueObjModifyChangeDetail;
import com.inspur.edp.cef.entity.entity.IMultiLanguageData;
import com.inspur.edp.cef.entity.entity.IValueObjData;
import com.inspur.edp.cef.entity.i18n.MultiLanguageInfo;

import java.util.Map;

public class ModifyAction extends AbstractAction<VoidActionResult>
{
	private IChangeDetail changeDetail;

	public ModifyAction(IBEContext beContext, IChangeDetail changeDetail)
	{
		super(beContext);
		this.changeDetail = changeDetail;
	}

	@Override
	public final void execute()
	{
		//① CurrentData为空，这说明未获取成功，抛异常；
		if (!ActionUtil.getBEContext(this).hasData())
		{
			throw new BefExceptionBase(
					ErrorCodes.ModifyingNonExistence, String.format("id为%1$s的数据不存在。", this.getBEContext().getID()), null, ExceptionLevel.Error, false);
		}
		AuthorityUtil.checkDataAuthority(
				(IBEContext) this.getBEContext());
		LockUtils.checkLock((IBEContext) this.getBEContext());

		switch (changeDetail.getChangeType())
		{
			case Added:
				throw new BefExceptionBase("Bef", "Modify操作不支持新增。", null, ExceptionLevel.Error, false);
			//case ChangeType.Deleted:
			//    DeleteAction.demandDeletePermission(Context);
			//    break;
			default:
				//DemandPermission(Context);
				break;
		}

		IChangeDetail currentChange = ActionUtil.getBEContext(this).getCurrentChange();
		if (currentChange != null)
		{
			switch (currentChange.getChangeType())
			{
				//case ChangeType.Added://② 无Modify时新增场景，若传入变更集/当前变更集为新增，抛异常；
				//    throw new BefExceptionBase("Bdf", "Modify操作不支持新增。");
				case Deleted: //③ 若当前变更集为删，抛异常；
					throw new BefExceptionBase(ErrorCodes.ModifyingNonExistence, "当前数据已添加删除标记，不支持再次执行Modify操作。", null, ExceptionLevel.Error, true);
				default: //④ 若当前变更集为改，接收改/删，将变更赋值给BEContext.ChangeFromModify；
					break;
			}

		}

		//TODO:[cef]先支持一层udt
		setNestedValue(changeDetail, this.getBEContext());
		ActionUtil.getRootEntity(this).appendTempCurrentChange(changeDetail);
		//AcceptModifyChangeDetail(changeDetail, BEContext.ChangeFromModify);
	}

	public static void setNestedValue(IChangeDetail change, IBENodeEntityContext context) {
		if(!(change instanceof ModifyChangeDetail)) {
			return;
		}
		ModifyChangeDetail modifyChange = (ModifyChangeDetail)change;
		if (modifyChange.getPropertyChanges() != null) {
			for (Map.Entry<String, Object> pair : modifyChange.getPropertyChanges().entrySet()) {
				if (pair.getValue() instanceof ValueObjModifyChangeDetail) {
					if (context.getCurrentData() == null) {
						throw new BefEngineException(ErrorCodes.ModifyingNonExistence,
								String.format("修改时，%s上数据获取失败：%s", context.getCode(), modifyChange.getDataID()),
								null);
					}
					Object tempVar = context.getCurrentData().getValue(pair.getKey());
					((ValueObjModifyChangeDetail)pair.getValue()).setData ( (IValueObjData)((tempVar instanceof IValueObjData) ? tempVar : null));
				}
			}
		}

		if(modifyChange.getMultiLanguageInfos() != null){
			for (Map.Entry<String, MultiLanguageInfo> pair : modifyChange.getMultiLanguageInfos().entrySet()){
				String propName = pair.getKey().split(MultiLanguageInfo.MULTILANGUAGETOKEN)[0];

				for (Map.Entry<String, Object> item : pair.getValue().getPropValueMap().entrySet()) {
					Object value = item.getValue();
					if (!(value instanceof ValueObjModifyChangeDetail))
						break;
					ValueObjModifyChangeDetail multiChange = (ValueObjModifyChangeDetail)value;
					IMultiLanguageData currentData = ((IMultiLanguageData)context.getCurrentData());
					if(!currentData.getMultiLanguageInfos().containsKey(pair.getKey())){
						currentData.getMultiLanguageInfos().put(pair.getKey(), new MultiLanguageInfo());
					}
					MultiLanguageInfo currentDataMultiInfo = currentData.getMultiLanguageInfos().get(pair.getKey());
					if(!currentDataMultiInfo.getPropValueMap().containsKey(item.getKey())){
						IValueObjData udtData = (IValueObjData)context.getCurrentData().getValue(propName);
						if(udtData == null)
							break;
						IValueObjData copyData = (IValueObjData)udtData.copy();
						currentDataMultiInfo.getPropValueMap().put(item.getKey(), copyData);
					}

					IValueObjData valueData = (IValueObjData)currentDataMultiInfo.getPropValueMap().get(item.getKey());
					for(Map.Entry<String, Object> changeItem :multiChange.getPropertyChanges().entrySet()){
						valueData.setValue(changeItem.getKey(), changeItem.getValue());
					}
					multiChange.setData(valueData);
				}
			}
		}

		if (modifyChange.getChildChanges() != null)
		{
for (Map.Entry<String, Map<String, IChangeDetail>> childChanges : modifyChange.getChildChanges().entrySet())
			{
for (Map.Entry<String, IChangeDetail> childChange : childChanges.getValue().entrySet())
				{
					if (!(childChange.getValue() instanceof ModifyChangeDetail))
					{
						continue;
					}
IBENodeEntityContext childContext = (IBENodeEntityContext)((IBENodeEntity)context.getDataType()).getChildBEEntity(childChanges.getKey(), childChange.getKey()).getContext();
					setNestedValue(childChange.getValue(), childContext);
				}
			}
		}
	}
	//private void acceptModifyChangeDetail(IChangeDetail source, IChangeDetail target)
	//{
	//    switch (source.getChangeType())
	//    {
	//        case ChangeType.Added:
	//            throw new BefExceptionBase("Bef", "Modify操作不支持新增。");
	//        case ChangeType.Deleted:
	//            DeleteAction.demandDeletePermission(BEContext);
	//            break;
	//        default:
	//            DemandPermission(BEContext);
	//            break;
	//    }
	//    BEContext.ChangeFromModify = ChangeDetailMerger.mergeChangeDetail(source, target);
	//    CoreBEContext.acceptChangeFromModify();
	//}

	@Override
	protected final IBEActionAssembler getAssembler()
	{
		return GetAssemblerFactory().getModifyActionAssembler((IBEContext) this.getBEContext(), changeDetail);
	}

	//internal static void DemandPermission(IBEContext beCtx)
	//{
	//    var com.inspur.edp.bef.core.assembler = ((IDefaultEntityActionAssFactory)beCtx.AbstractActionAssemblerFactory).getModifyActionAssembler(beCtx, null);
	//    if (com.inspur.edp.bef.core.assembler == null) return;
	//    if (!com.inspur.edp.bef.core.assembler.demandDataPermission(beCtx.CurrentData))
	//        throw new BefDataPermissionDeniedException();
	//}
}
